
package com.huaweicloud.saaslanding.install.applicationservice.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.huaweicloud.saaslanding.basic.constant.GlobalConstant;
import com.huaweicloud.saaslanding.basic.database.mybatis.conditions.query.QueryWrap;
import com.huaweicloud.saaslanding.basic.enumeration.IdaasEnum;
import com.huaweicloud.saaslanding.basic.enumeration.combo.PackageStatusEnum;
import com.huaweicloud.saaslanding.basic.enumeration.tenant.TenantTypeEnum;
import com.huaweicloud.saaslanding.basic.exception.BizException;
import com.huaweicloud.saaslanding.basic.exception.code.ExceptionCode;
import com.huaweicloud.saaslanding.basic.idaas.IdaasOperator;
import com.huaweicloud.saaslanding.basic.idaas.model.MessageInfo;
import com.huaweicloud.saaslanding.basic.idaas.request.IdaasOrg;
import com.huaweicloud.saaslanding.basic.idaas.request.IdaasUser;
import com.huaweicloud.saaslanding.basic.idaas.request.Register;
import com.huaweicloud.saaslanding.basic.idaas.response.InitConsoleAppResponse;
import com.huaweicloud.saaslanding.basic.oneaccess.http.OneAccessHttpClient;
import com.huaweicloud.saaslanding.basic.utils.BeanPlusUtil;
import com.huaweicloud.saaslanding.basic.utils.CheckNullUtil;
import com.huaweicloud.saaslanding.basic.utils.DateUtils;
import com.huaweicloud.saaslanding.basic.utils.EncryptionUtil;
import com.huaweicloud.saaslanding.basic.utils.ThreadPoolManager;
import com.huaweicloud.saaslanding.dao.common.entity.app.AppDeployment;
import com.huaweicloud.saaslanding.dao.common.entity.app.AppPackage;
import com.huaweicloud.saaslanding.dao.common.entity.app.AppTemplate;
import com.huaweicloud.saaslanding.dao.common.entity.master.AppAccount;
import com.huaweicloud.saaslanding.dao.common.entity.master.Org;
import com.huaweicloud.saaslanding.dao.common.entity.master.Role;
import com.huaweicloud.saaslanding.dao.common.entity.master.User;
import com.huaweicloud.saaslanding.dao.common.entity.master.UserRole;
import com.huaweicloud.saaslanding.dao.common.entity.security.WorkSecretKey;
import com.huaweicloud.saaslanding.dao.common.entity.tenant.SubscribedApp;
import com.huaweicloud.saaslanding.dao.common.entity.tenant.Tenant;
import com.huaweicloud.saaslanding.dao.common.entity.tenant.TenantApp;
import com.huaweicloud.saaslanding.dao.common.entity.tenant.TenantSubscribableAppPackage;
import com.huaweicloud.saaslanding.dao.common.repository.app.AppDeploymentBaseMapper;
import com.huaweicloud.saaslanding.dao.common.repository.app.AppPackageBaseMapper;
import com.huaweicloud.saaslanding.dao.common.repository.app.AppTemplateBaseMapper;
import com.huaweicloud.saaslanding.dao.common.repository.master.AppAccountBaseMapper;
import com.huaweicloud.saaslanding.dao.common.repository.master.OrgBaseMapper;
import com.huaweicloud.saaslanding.dao.common.repository.master.RoleBaseMapper;
import com.huaweicloud.saaslanding.dao.common.repository.master.UserBaseMapper;
import com.huaweicloud.saaslanding.dao.common.repository.master.UserRoleBaseMapper;
import com.huaweicloud.saaslanding.dao.common.repository.tenant.SubscribedAppBaseMapper;
import com.huaweicloud.saaslanding.dao.common.repository.tenant.TenantAppBaseMapper;
import com.huaweicloud.saaslanding.dao.common.repository.tenant.TenantBaseMapper;
import com.huaweicloud.saaslanding.dao.common.repository.tenant.TenantSubscribableAppPackageBaseMapper;
import com.huaweicloud.saaslanding.install.applicationservice.IdaasService;
import com.huaweicloud.saaslanding.install.constant.OneAccessConstant;
import com.huaweicloud.saaslanding.install.dto.IdaasDto;
import com.huaweicloud.saaslanding.install.dto.IdaasOrganizationDto;
import com.huaweicloud.saaslanding.install.dto.SaltDto;
import com.huaweicloud.saaslanding.install.dto.UserAndTenantAndRole;
import com.huaweicloud.saaslanding.install.properties.Iam;
import com.huaweicloud.saaslanding.install.properties.Idaas;
import com.huaweicloud.saaslanding.install.properties.idaas.IdaasOrganization;
import com.huaweicloud.saaslanding.install.properties.idaas.IdaasUserProperties;
import com.huaweicloud.saaslanding.install.repository.WorkSecretKeyMapper;
import com.huaweicloud.saaslanding.install.util.DomainNameUtil;
import com.huaweicloud.saaslanding.install.util.SaltUtil;

import cn.hutool.core.util.ObjectUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * 功能描述
 *
 * @since 2022-03-23
 */

@Slf4j
@Component
public class IdaasServiceImpl implements IdaasService {

    /**
     * 标记某个组织下的用户
     */
    public static final Integer USER_ORG = 4;

    /**
     * 标记某个父组织下所有子组织
     */
    public static final Integer ALONE_ORG = 3;

    /**
     * 初始化线程池
     */
    protected ThreadPoolExecutor poolExecutor = ThreadPoolManager.newInstance();

    @Resource
    private Iam iam;

    @Resource
    private Idaas idaas;

    @Resource
    private IdaasUserProperties idaasUserProperties;

    @Resource
    private IdaasOrganization idaasOrganization;

    @Resource
    private OneAccessConstant oneAccessConstant;

    @Autowired
    private IdaasOperator idaasOperator;

    @Autowired
    private SubscribedAppBaseMapper subscribedAppBaseMapper;

    @Autowired
    private WorkSecretKeyMapper workSecretKeyMapper;

    @Autowired
    private OneAccessHttpClient oneAccessHttpClient;

    @Resource
    TenantAppBaseMapper tenantAppBaseMapper;

    @Resource
    AppDeploymentBaseMapper appDeploymentBaseMapper;

    @Resource
    AppTemplateBaseMapper appTemplateBaseMapper;

    @Resource
    SaltUtil saltUtil;

    @Autowired
    private UserBaseMapper userBaseMapper;

    @Autowired
    private RoleBaseMapper roleBaseMapper;

    @Autowired
    private AppAccountBaseMapper appAccountBaseMapper;

    @Autowired
    private OrgBaseMapper orgBaseMapper;

    @Autowired
    private UserRoleBaseMapper userRoleBaseMapper;

    @Resource
    private TransactionTemplate transactions;

    @Autowired
    private TenantBaseMapper tenantBaseMapper;

    @Autowired
    private AppPackageBaseMapper appPackageBaseMapper;

    @Autowired
    private TenantSubscribableAppPackageBaseMapper tenantSubscribableAppPackageBaseMapper;

    @Value("${saaslanding-install.database.connection-info.db-name}")
    private String dbName;

    private MessageInfo getMessageInfo() {
        // 获取应用（idaas ClientId以及ClientSecret）
        SubscribedApp isvConsoleSubApp = subscribedAppBaseMapper
            .selectOne(new QueryWrapper<SubscribedApp>().eq(GlobalConstant.IS_DEL, 0).eq("is_console", 1));
        MessageInfo messageInfo = new MessageInfo();
        messageInfo.setIdaasClientId(isvConsoleSubApp.getIdaasClientId());

        String tenantCode = dbName;
        WorkSecretKey hslWorkSecretKey = workSecretKeyMapper
            .selectOne(new QueryWrapper<WorkSecretKey>().eq("tenant_code", tenantCode).eq("is_del", 0));
        String salt = EncryptionUtil.decrypt(hslWorkSecretKey.getPwdSalt(), hslWorkSecretKey.getPassword());
        messageInfo.setIdaasClientSecret(EncryptionUtil.decrypt(salt, isvConsoleSubApp.getIdaasClientSecret()));
        WorkSecretKey redisWorkSecretKey =
            workSecretKeyMapper.selectOne(new QueryWrapper<WorkSecretKey>().eq("is_redis", 1).eq("is_del", 0));
        messageInfo.setRedisPwd(redisWorkSecretKey.getPassword());
        messageInfo.setRedisPwdSalt(redisWorkSecretKey.getPwdSalt());
        messageInfo.setTenantCode(tenantCode);

        if (IdaasEnum.IdaasTypeEnum.ONE_ACCESS.getName().equals(idaas.getType())) {
            messageInfo.setDomain(idaas.getOneaccess().getDomain());
        }
        return messageInfo;
    }

    @Override
    public void deleteUser(String userId) {
        idaasOperator.deleteUser(userId, getMessageInfo());
    }

    @Override
    public String addUser(IdaasUser idaasUser) {
        return idaasOperator.addUser(idaasUser, getMessageInfo());
    }

    @Override
    public String accountForUser(String userId, String appId) {
        return idaasOperator.accountForUser(userId, appId, getMessageInfo());
    }

    @Override
    public void getAndDeleteUser(String userId) {
        idaasOperator.getAndDeleteUser(userId, getMessageInfo());
    }

    @Override
    public IdaasOrg getOrganization(String orgId) {
        return idaasOperator.getOrg(orgId, getMessageInfo());
    }

    @Override
    public String addOrganization(IdaasOrg idaasOrg) {
        return idaasOperator.addOrg(idaasOrg, getMessageInfo());
    }

    @Override
    public void deleteOrganization(String orgId) {
        idaasOperator.deleteOrg(orgId, getMessageInfo());
    }

    @Override
    public void getAndDeleteOrg(String orgId) {
        idaasOperator.getAndDeleteOrg(orgId, getMessageInfo());
    }

    @Override
    public void getAndDeleteAccount(String appId, String accountId) {
        idaasOperator.getAndDeleteAccount(appId, accountId, getMessageInfo());
    }

    @Override
    public Map<String, String> registerOneAccess() {
        String orgId = "";
        String userId = "";
        String accountId = "";
        Map<String, String> idMap;
        try {
            IdaasOrg idaasOrg = setIdaasOrg();
            // 新增组织
            orgId = addOrganization(idaasOrg);
            idaasUserProperties.setOrgCode(idaasOrganization.getOrgCode());
            // 在该组织下新增用户
            IdaasUser idaasUser = setIdaasUser();
            userId = addUser(idaasUser);
            // 添加应用账号
            String oneAccessAppId = idaas.getApplicationHttpsConsole().getAppId();
            accountId = accountForUser(userId, oneAccessAppId);
            idMap = new HashMap<>();
            idMap.put(OneAccessConstant.ORG_ID, orgId);
            idMap.put(OneAccessConstant.USER_ID, userId);
            idMap.put(OneAccessConstant.ACCOUNT_ID, accountId);
        } catch (BizException e) {

            String oneAccessAppId = idaas.getApplicationHttpsConsole().getAppId();

            getAndDeleteAccount(oneAccessAppId, accountId);
            getAndDeleteUser(userId);
            try {
                log.info("oneaccess用户删除中-----------");
                Thread.sleep(2000);
                log.info("oneaccess用户删除成功-----------");
            } catch (Exception th) {
                log.error("线程sleep错误");
            }
            getAndDeleteOrg(orgId);
            throw new BizException(e.getCode(), e.getMessage());
        }
        return idMap;
    }

    private IdaasUser setIdaasUser() {
        IdaasUser idaasUser = new IdaasUser();
        idaasUser.setUserId(idaasUserProperties.getUserId());
        idaasUser.setUserName(idaasUserProperties.getUserName());
        idaasUser.setName(idaasUserProperties.getName());
        idaasUser.setMobile(idaasUserProperties.getMobile());
        idaasUser.setEmail(idaasUserProperties.getEmail());
        idaasUser.setOrgCode(idaasUserProperties.getOrgCode());
        idaasUser.setDisabled(idaasUserProperties.getDisabled());
        idaasUser.setPassword(idaasUserProperties.getPassword());
        idaasUser.setPwdMustModify(idaasUserProperties.isPwdMustModify());
        idaasUser.setOrgId(idaasUserProperties.getOrgId());
        idaasUser.setTenantName(idaasUserProperties.getOrgCode());
        return idaasUser;
    }

    @Override
    public String getChildren(String orgId, Integer offset, Integer limit) {
        return getList(limit, offset, true, orgId);
    }

    @Override
    public String getOrgAlone(Integer offset, Integer limit, String orgId) {
        return getChildren(orgId, offset, limit);
    }

    /**
     * 查询组织列表1
     *
     * @param limit 每页数量。 最小值：10 最大值：100
     * @param offset 分页偏移量，表示从此偏移量开始查询， offset大于等于0。
     * @param allChild 是否获取所有层级子组织。
     * @param orgId 组织机构id，获取指定机构及其下的子机构。如果不传递，查询所有根组织。
     * @return 组织列表信息（json）
     */
    private String getList(Integer limit, Integer offset, Boolean allChild, String orgId) {
        // 对每页数目进行判断
        if (limit < OneAccessConstant.LIMIT_MIN || limit > OneAccessConstant.LIMIT_MAX) {
            throw new BizException(ExceptionCode.ONEACCESS_LIMIT_ORG_FAILED.getCode(),
                ExceptionCode.ONEACCESS_LIMIT_ORG_FAILED.getMsg());
        }
        // 对偏移量进行判断
        if (offset < 0) {
            throw new BizException(ExceptionCode.ONEACCESS_OFFSET_ORG_FAILED.getCode(),
                ExceptionCode.ONEACCESS_OFFSET_ORG_FAILED.getMsg());
        }
        // 入参空值处理
        orgId = orgId == null ? "" : orgId;
        allChild = allChild != null;

        StringBuilder urlBuilder = new StringBuilder(oneAccessConstant.getOrganizationListUrl);
        urlBuilder.append("?limit=")
            .append(limit)
            .append("&offset=")
            .append(offset)
            .append("&all_child=")
            .append(allChild)
            .append("&org_id=")
            .append(orgId);
        String url = urlBuilder.toString();
        return oneAccessHttpClient.doGetNoArgs(url, getMessageInfo());
    }

    @Override
    public JSONArray getAloneOrg(String orgId) {
        String json = getChildren(orgId, 0, 100);
        String listName = "organizations";
        return getOneAccessList(json, listName, ALONE_ORG, orgId);
    }

    @Override
    public InitConsoleAppResponse initConsoleApp(String idaasAppId, String orgCode, String orgName,
        MessageInfo messageInfo) {
        return idaasOperator.initConsoleApp(idaasAppId, orgCode, orgName, messageInfo);
    }

    @Override
    public String initConsoleContinue(Register register, MessageInfo messageInfo) {
        return idaasOperator.initConsoleContinue(register, messageInfo);
    }

    @Override
    public void registerRollback(Register register, String orgId, MessageInfo messageInfo) {
        idaasOperator.registerRollback(register, orgId, messageInfo);
    }

    @Override
    public void batchDeleteOrg(List<IdaasOrganizationDto> oneAccessOrganizationLists) {
        // 过滤和格式化数据
        List<List<String>> list = filterAndFormatOrg(oneAccessOrganizationLists);

        if (CheckNullUtil.isNull(list)) {
            return;
        }
        // 调用多线程从最底层组织开始删除
        log.info("-----------------开始多线程批量删除组织----------------");
        list.forEach(this::multiThreadDelete);
        log.info("-----------------多线程批量删除成功----------------");
    }

    private void multiThreadDelete(List<String> orgIdList) {
        // stream->多线程执行user删除
        CompletableFuture<?>[] cfs = orgIdList.stream()
            .map(orgId -> CompletableFuture.runAsync(() -> getAndDeleteOrg(orgId), poolExecutor).thenAccept(v -> {
            }).exceptionally(e -> {
                // 截取错误信息
                log.error(e.getMessage(), e.toString());
                throw new BizException(e);
            }))
            .toArray(CompletableFuture[]::new);
        // 等待总任务完成，但是无返回值，必须whenComplete()获取
        CompletableFuture.allOf(cfs).join();
    }

    private List<List<String>> filterAndFormatOrg(List<IdaasOrganizationDto> oneAccessOrganizationLists) {
        if (CheckNullUtil.isNull(oneAccessOrganizationLists)) {
            return new ArrayList<>();
        }
        // 一层组织id集合
        List<String> rootIdAllList = oneAccessOrganizationLists.stream()
            .filter(n -> CheckNullUtil.isNull(n.getParentId()))
            .map(IdaasOrganization::getOrgId)
            .collect(Collectors.toList());
        // 子组织集合
        List<IdaasOrganizationDto> childIdAllList = oneAccessOrganizationLists.stream()
            .filter(n -> CheckNullUtil.isNotNull(n.getParentId()))
            .collect(Collectors.toList());
        // 判断子组织是否全为空
        if (CheckNullUtil.isNull(childIdAllList)) {
            List<List<String>> rootAll = new ArrayList<>();
            rootAll.add(rootIdAllList);
            return rootAll;
        }
        List<String> rootList = getRootIdAllList(oneAccessOrganizationLists, childIdAllList, rootIdAllList);
        // 符合格式的组织集合
        List<List<String>> orgList = new ArrayList<>();
        orgList.add(rootList);
        List<List<String>> allIdList = orgToList(rootList, childIdAllList, orgList);
        Collections.reverse(allIdList);
        return allIdList;
    }

    private List<String> getRootIdAllList(List<IdaasOrganizationDto> oneAccessOrganizationLists,
        List<IdaasOrganizationDto> allList, List<String> rootIdAllList) {
        // 判断一层组织是否在入参的list中
        List<String> rootList = oneAccessOrganizationLists.stream()
            .map(IdaasOrganization::getOrgId)
            .filter(rootIdAllList::contains)
            .collect(Collectors.toList());
        // 如果入参中的list没有一层组织,那么进行从子组织中找到其中的第一层组织
        if (CheckNullUtil.isNull(rootList)) {
            List<String> parentIdList = allList.stream().map(IdaasOrganization::getParentId).toList();
            rootList = allList.stream()
                .map(IdaasOrganization::getOrgId)
                .filter(orgId -> !parentIdList.contains(orgId))
                .collect(Collectors.toList());
        }
        return rootList;
    }

    /**
     * 将组织变为List[[最底l子组织],[上一层子组织]......[根组织]]
     *
     * @param orgIdList 根组织id集合
     * @param orgList 所有子组织
     * @param all 要填充的list （返回值）
     * @return 要返回的符合格式的组织集合
     */
    private List<List<String>> orgToList(List<String> orgIdList, List<IdaasOrganizationDto> orgList,
        List<List<String>> all) {
        List<IdaasOrganizationDto> list = orgList.stream().filter(e -> orgIdList.contains(e.getParentId())).toList();
        List<String> newOrgIdList = list.stream().map(IdaasOrganization::getOrgId).collect(Collectors.toList());
        if (list.size() != 0) {
            all.add(newOrgIdList);
            orgToList(newOrgIdList, orgList, all);
        }
        // 将实体集合转为id集合
        return all;
    }

    @Override
    public String getUserListInOrg(Integer offset, Integer limit, String orgId) {
        limitAndOffset(offset, limit);
        // 拼接url
        String url = oneAccessConstant.getUserListUrl.concat("?")
            .concat("limit=")
            .concat(String.valueOf(limit))
            .concat("&offset=")
            .concat(String.valueOf(offset))
            .concat("&org_id=")
            .concat(orgId);

        // 和oneAccessAPI建立连接,获取结果
        return oneAccessHttpClient.doGetNoArgs(url, getMessageInfo());
    }

    private void limitAndOffset(Integer offset, Integer limit) {
        // 对每页数目进行判断
        if (limit < OneAccessConstant.LIMIT_MIN || limit > OneAccessConstant.LIMIT_MAX) {
            throw new BizException(ExceptionCode.ONEACCESS_LIMIT_USER_FAILED.getCode(),
                ExceptionCode.ONEACCESS_LIMIT_USER_FAILED.getMsg());
        }
        // 对偏移量进行判断
        if (offset < 0) {
            throw new BizException(ExceptionCode.ONEACCESS_OFFSET_USER_FAILED.getCode(),
                ExceptionCode.ONEACCESS_OFFSET_USER_FAILED.getMsg());
        }
    }

    @Override
    public void batchDeleteUser(List<IdaasUserProperties> idaasUserPropertiesList) {
        if (CheckNullUtil.isNull(idaasUserPropertiesList)) {
            return;
        }
        log.info("-----------------开始多线程批量删除用户----------------");
        // stream->多线程执行user删除
        CompletableFuture<?>[] cfs = idaasUserPropertiesList.stream()
            .map(idaasUserProperties -> CompletableFuture
                .runAsync(() -> deleteUser(idaasUserProperties.getUserId()), poolExecutor)
                .thenAccept(v -> {
                })
                .exceptionally(e -> {
                    // 截取错误信息
                    log.error(e.getMessage(), e.toString());
                    throw new BizException(e);
                }))
            .toArray(CompletableFuture[]::new);
        // 等待总任务完成，但是无返回值，必须whenComplete()获取
        CompletableFuture.allOf(cfs).join();
        log.info("-----------------多线程批量用户删除成功----------------");
    }

    @Override
    public JSONArray getAllUser(String orgId) {
        // 获取oneaccess部分列表：用于获取oneaccess用户条数
        String json = getUserListInOrg(0, 100, orgId);
        // 返回的json串信息中用户列表的key
        String listName = "users";
        return getOneAccessList(json, listName, USER_ORG, orgId);
    }

    @Override
    public void initIdaasInfo() {
        log.info("----------------开始初始化Idaas-------------------");
        User user = new User();

        Tenant tenant = new Tenant().setIsBuiltIn(true)
            .setEnabled(true)
            .setIsConverted(false)
            .setType(TenantTypeEnum.BUILT_IN.getType())
            .setAlias(dbName)
            .setExpireTime(DateUtils.NEVER_EXPIRE_DATETIME);
        tenant.setIsSelfDomain(true).setDomainName(DomainNameUtil.getDomainName());
        Org org = new Org();
        AppAccount appAccount = new AppAccount();
        UserRole userRole = new UserRole();
        // 盐加密
        String jasyptPassword = saltUtil.findJasypt();
        String password = EncryptionUtil.encrypt(jasyptPassword, idaasUserProperties.getPassword());
        String idaasTenantId = "";
        String idaasUserId = "";
        String idaasAccountId = "";
        // 先注册idaas,获取用户id和组织id和应用账号id(先查询数据库中是否有对应信息)-无则全部添加,有再判断应用账号
        Long userId = null;
        Long tenantId = null;
        List<Tenant> idListOrg = getTenantId();
        if (CheckNullUtil.isNotNull(idListOrg)) {
            tenantId = idListOrg.get(0).getId();
        }
        SubscribedApp subApp = getSubApp();
        if (CheckNullUtil.isNull(subApp)) {
            throw new BizException("idaas应用信息错误,请核对配置文件应用信息,或clean后重新install");
        }
        List<User> idList = getUserId();
        if (CheckNullUtil.isNotNull(idList)) {
            userId = getUserId().get(0).getId();
        }
        List<AppAccount> accountIds = getAccountId(userId, subApp.getId());
        // 获取应用账号id 和 获取oneAccess应用账号id
        if (CheckNullUtil.isNotNull(accountIds)) {
            idaasAccountId = accountIds.get(0).getIdaasAccountId();
        }
        Long roleId = getRoleId(subApp.getId());
        UserAndTenantAndRole userAndTenantAndRole = new UserAndTenantAndRole();
        userAndTenantAndRole.setSalt(jasyptPassword);
        // 增加云商店接入码
        userAndTenantAndRole.setCmAccessKey(EncryptionUtil.encrypt(jasyptPassword, iam.getCloudMarketAccesskey()));
        setUserAndTenantAndRole(user, tenant, org, appAccount, userRole, idaasUserId, idaasAccountId,
            userAndTenantAndRole);
        setUserAndTenantAndRole(idaasTenantId, userId, tenantId, subApp.getId(), roleId, userAndTenantAndRole);
        setUserAndTenantAndRole(password, idListOrg, idList, userAndTenantAndRole);
        // 获取oneaccess信息
        Map<String, String> idMap = accountIsExit(userAndTenantAndRole);

        idaasAccountId = idMap.get("idaasAccountId");
        idaasUserId = idMap.get("idaasUserId");
        idaasTenantId = idMap.get("idaasTenantId");
        String idaasClientId = idMap.get("idaasClientId");
        String idaasClientSecret = idMap.get("idaasClientSecret");
        // 开始事务，如果出现事务，则回滚
        IdaasDto idaasDtoParam = new IdaasDto();
        idaasDtoParam.setIdaasClientId(idaasClientId);
        idaasDtoParam.setIdaasClientSecret(idaasClientSecret);
        idaasDtoParam.setIdaasAppId(subApp.getIdaasAppId());
        idaasDtoParam.setAppId(subApp.getAppId());
        setInsertDbOne(user, tenant, org, appAccount, userRole, idaasAccountId, idaasUserId, idaasDtoParam);
        setInsertDbTwo(subApp, roleId, idaasTenantId, userId, tenantId, idaasDtoParam);
        // 插库
        insertDb(idaasDtoParam);
    }

    @Override
    public void deleteIdaasInfo() {
        log.info("-----------------开始删除<{}>信息---------------------", idaas.getType());
        try {
            if (IdaasEnum.IdaasTypeEnum.ONE_ACCESS.getName().equals(idaas.getType())) {
                cleanOneAccessAll();
            } else {
                cleanKeyCloakAll();
            }
            log.info("-----------------<{}>信息删除成功------------------", idaas.getType());
        } catch (BizException e) {
            log.error("-----------------<{}>信息删除失败------------------\n错误信息：{}", idaas.getType(), e.getMessage());
            throw new BizException(e);
        }
    }

    private void cleanOneAccessAll() {
        // 获取应用id
        SubscribedApp subApp = getSubApp();
        // 如果两者都存在的话,执行删除操作
        if (CheckNullUtil.isNotNull(subApp)) {
            // 删除所有用户和组织-开启事务，如果失败，事务回滚
            transactions.execute(account -> {
                try {
                    batchDeleteUser(getAllUser());
                    log.info("oneaccess用户删除中-----------");
                    Thread.sleep(3000);
                    log.info("oneaccess用户删除成功-----------");
                    batchDeleteOrg(getAllOrg());
                } catch (Exception e) {
                    log.info("oneaccess用户删除失败：{}", e.getMessage());
                    account.setRollbackOnly();
                    throw new BizException("------------------------oneAccess信息删除失败----------------------------------");
                }
                return 1;
            });
        }
    }

    private void cleanKeyCloakAll() {
        // 查询所有的租户
        QueryWrapper<Tenant> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(GlobalConstant.IS_DEL, false);
        List<Tenant> tenants = tenantBaseMapper.selectList(queryWrapper);
        for (Tenant tenant : tenants) {
            try {
                // keycloak删除领域即可
                registerRollback(null, tenant.getIdaasTenantId(), getMessageInfo());
            } catch (Exception e) {
                log.error("删除领域失败");
                log.error(e.getMessage(), e);
            }
        }
    }

    private void setUserAndTenantAndRole(String password, List<Tenant> idListOrg, List<User> idList,
        UserAndTenantAndRole userAndTenantAndRole) {
        userAndTenantAndRole.setPassword(password);
        userAndTenantAndRole.setIdListOrg(idListOrg);
        userAndTenantAndRole.setIdList(idList);
    }

    private void setUserAndTenantAndRole(String oneAccessTenantId, Long userId, Long tenantId, Long appId, Long roleId,
        UserAndTenantAndRole userAndTenantAndRole) {
        userAndTenantAndRole.setUserId(userId)
            .setIdaasTenantId(oneAccessTenantId)
            .setAppId(appId)
            .setRoleId(roleId)
            .setTenantId(tenantId);
    }

    private void setUserAndTenantAndRole(User user, Tenant tenant, Org org, AppAccount hslAppAccount, UserRole userRole,
        String idaasUserId, String idaasAccountId, UserAndTenantAndRole userAndTenantAndRole) {
        userAndTenantAndRole.setUser(user)
            .setTenant(tenant)
            .setOrg(org)
            .setHslAppAccount(hslAppAccount)
            .setUserRole(userRole)
            .setIdaasUserId(idaasUserId)
            .setIdaasAccountId(idaasAccountId);
    }

    private void setInsertDbOne(User user, Tenant tenant, Org org, AppAccount hslAppAccount, UserRole userRole,
        String finalOneAccessAccountId, String finalOneAccessUserId, IdaasDto idaasDto) {
        idaasDto.setUser(user)
            .setTenant(tenant)
            .setOrg(org)
            .setHslAppAccount(hslAppAccount)
            .setUserRole(userRole)
            .setFinalOneAccessUserId(finalOneAccessUserId)
            .setFinalOneAccessAccountId(finalOneAccessAccountId);
    }

    private void setInsertDbTwo(SubscribedApp subscribedApp, Long roleId, String finalOneAccessTenantId,
        Long finalUserId, Long finalTenantId, IdaasDto idaasDto) {
        idaasDto.setUserId(finalUserId)
            .setFinalOneAccessTenantId(finalOneAccessTenantId)
            .setSubAppId(subscribedApp.getId())
            .setRoleId(roleId)
            .setTenantId(finalTenantId)
            .setAppId(subscribedApp.getAppId());
    }

    private Map<String, String> accountIsExit(UserAndTenantAndRole userAndTenantAndRole) {
        String idaasClientId = null;
        String idaasClientSecret = null;
        if (CheckNullUtil.isNull(userAndTenantAndRole.getUserId())
            && CheckNullUtil.isNull(userAndTenantAndRole.getTenantId())
            && CheckNullUtil.isNull(getAccountId(userAndTenantAndRole.getUserId(), userAndTenantAndRole.getAppId()))) {
            // oneAccess进行注册，获取oneAccessUserId和oneAccessTenantId和oneAccessAccountId
            try {
                AppTemplate saasAppTemplate = appTemplateBaseMapper.getSaasAppInfo();
                // 判断是oneaccess还是keycloak
                Map<String, String> idMap = new HashMap<>();
                if (IdaasEnum.IdaasTypeEnum.ONE_ACCESS.getName().equals(idaas.getType())) {
                    idMap = registerOneAccess();
                    idaasClientId = saasAppTemplate.getIdaasClientId();
                    idaasClientSecret = saasAppTemplate.getIdaasClientSecret();
                    userAndTenantAndRole.getOrg().setIdaasOrgId(idMap.get(OneAccessConstant.ORG_ID));
                } else {
                    MessageInfo messageInfo = getMessageInfo();
                    InitConsoleAppResponse initConsoleAppResponse = initConsoleApp(saasAppTemplate.getIdaasAppId(),
                        idaasOrganization.getOrgCode(), idaasOrganization.getName(), messageInfo);

                    // 原来从数据库获取的client不正确，重新set一遍正确的值
                    messageInfo.setIdaasClientId(initConsoleAppResponse.getClientId());
                    messageInfo.setIdaasClientSecret(initConsoleAppResponse.getClientSecret());

                    // 对ClientSecret进行加密
                    String encryptedSecret = EncryptionUtil.encrypt(userAndTenantAndRole.getSalt(),
                        initConsoleAppResponse.getClientSecret());
                    initConsoleAppResponse.setClientSecret(encryptedSecret);

                    IdaasOrg idaasOrg = setIdaasOrg();
                    // 新增组织
                    String orgId = addOrganization(idaasOrg);
                    userAndTenantAndRole.getOrg().setIdaasOrgId(orgId);

                    // keycloak中还需要更新subscribedApp表中client相关数据
                    QueryWrapper<SubscribedApp> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq(GlobalConstant.IS_DEL, false);
                    SubscribedApp hslSubscribedApp = subscribedAppBaseMapper.selectOne(queryWrapper);
                    hslSubscribedApp.setIdaasClientId(initConsoleAppResponse.getClientId());
                    hslSubscribedApp.setIdaasClientSecret(initConsoleAppResponse.getClientSecret());
                    subscribedAppBaseMapper.updateById(hslSubscribedApp);

                    Register register = setRegister(saasAppTemplate);
                    String idaasUserId = initConsoleContinue(register, messageInfo);
                    idMap.put(OneAccessConstant.ORG_ID, initConsoleAppResponse.getTenantId());
                    idMap.put(OneAccessConstant.USER_ID, idaasUserId);
                    idMap.put(OneAccessConstant.ACCOUNT_ID, idaasUserId);
                    idaasClientId = initConsoleAppResponse.getClientId();
                    idaasClientSecret = initConsoleAppResponse.getClientSecret();
                }
                userAndTenantAndRole.setIdaasTenantId(idMap.get(OneAccessConstant.ORG_ID));
                userAndTenantAndRole.setIdaasUserId(idMap.get(OneAccessConstant.USER_ID));
                userAndTenantAndRole.setIdaasAccountId(idMap.get(OneAccessConstant.ACCOUNT_ID));

                // 插入用户和企业实体
                insertUserAndTenant(userAndTenantAndRole.getUser(), userAndTenantAndRole.getTenant(),
                    userAndTenantAndRole.getOrg(), userAndTenantAndRole.getPassword(),
                    userAndTenantAndRole.getIdaasTenantId(), userAndTenantAndRole.getIdaasUserId(),
                    userAndTenantAndRole.getCmAccessKey(), userAndTenantAndRole.getOrg().getIdaasOrgId());

            } catch (Exception e) {
                userAndTenantRollBack(userAndTenantAndRole.getIdaasTenantId(), userAndTenantAndRole.getIdaasUserId(),
                    userAndTenantAndRole.getIdaasAccountId(), e);
            }

        }
        // 判断应用账号是否存在:存在不处理，不存在添加
        if (CheckNullUtil.isNotNull(userAndTenantAndRole.getUserId())
            && CheckNullUtil.isNotNull(userAndTenantAndRole.getTenantId())
            && CheckNullUtil.isNull(getAccountId(userAndTenantAndRole.getUserId(), userAndTenantAndRole.getAppId()))) {
            try {
                String oneAccessAppId = idaas.getApplicationHttpsConsole().getAppId();
                userAndTenantAndRole.setIdaasUserId(userAndTenantAndRole.getIdList().get(0).getIdaasUserId());
                userAndTenantAndRole.setIdaasTenantId(userAndTenantAndRole.getIdListOrg().get(0).getIdaasTenantId());
                userAndTenantAndRole
                    .setIdaasAccountId(accountForUser(userAndTenantAndRole.getIdaasUserId(), oneAccessAppId));
                // 插入角色和应用实体
                insertAppAndRole(userAndTenantAndRole.getHslAppAccount(), userAndTenantAndRole.getUserRole(),
                    userAndTenantAndRole.getIdaasAccountId(), userAndTenantAndRole.getUserId(),
                    userAndTenantAndRole.getRoleId(), userAndTenantAndRole.getAppId());
            } catch (BizException e) {
                registerOneaccessRollBack(userAndTenantAndRole.getIdaasTenantId(),
                    userAndTenantAndRole.getIdaasUserId(), userAndTenantAndRole.getIdaasAccountId());
            }
        }
        HashMap<String, String> oneaccessInformation = new HashMap<>();
        oneaccessInformation.put("idaasUserId", userAndTenantAndRole.getIdaasUserId());
        oneaccessInformation.put("idaasTenantId", userAndTenantAndRole.getIdaasTenantId());
        oneaccessInformation.put("idaasAccountId", userAndTenantAndRole.getIdaasAccountId());
        oneaccessInformation.put("idaasClientId", idaasClientId);
        oneaccessInformation.put("idaasClientSecret", idaasClientSecret);

        return oneaccessInformation;
    }

    private IdaasOrg setIdaasOrg() {
        IdaasOrg idaasOrg = new IdaasOrg();
        idaasOrg.setOrgCode(idaasOrganization.getOrgCode());
        idaasOrg.setOrgId(idaasOrganization.getOrgId());
        idaasOrg.setParentId(idaasOrganization.getParentId());
        idaasOrg.setName(idaasOrganization.getName());
        return idaasOrg;
    }

    private Register setRegister(AppTemplate saasAppTemplate) {
        Register register = new Register();
        register.setMobile(idaasUserProperties.getMobile())
            .setUserName(idaasUserProperties.getUserName())
            .setOrgName(idaasOrganization.getName())
            .setOrgCode(idaasOrganization.getOrgCode())
            .setPassword(idaasUserProperties.getPassword())
            .setIdaasAppId(saasAppTemplate.getIdaasAppId());
        return register;
    }

    private void insertDb(IdaasDto idaasDtoParam) {
        transactions.execute(ts -> {
            idaasDtoParam.setTs(ts);
            insertDbReally(idaasDtoParam);
            return 1;
        });
    }

    private void userAndTenantRollBack(String idaasTenantId, String idaasUserId, String idaasAccountId, Exception e) {
        log.error(e.getMessage(), e);
        // 报错回滚，删除之前的oneAccess数据
        log.info("oneaccess插入失败,开始回滚");
        String oneAccessAppId = idaas.getApplicationHttpsConsole().getAppId();
        getAndDeleteAccount(oneAccessAppId, idaasAccountId);
        getAndDeleteUser(idaasUserId);
        try {
            log.info("oneaccess用户删除中-----------");
            Thread.sleep(2000);
            log.info("oneaccess用户删除成功-----------");
        } catch (Exception th) {
            log.error("线程sleep错误");
        }
        getAndDeleteOrg(idaasTenantId);
        throw new BizException(ExceptionCode.ONEACCESS_ADD_USER_FAILED.getCode(), e.getMessage());
    }

    private void registerOneaccessRollBack(String idaasTenantId, String idaasUserId, String oneAccessAccountId) {
        getAndDeleteUser(idaasUserId);
        try {
            log.info("oneaccess用户删除中-----------");
            Thread.sleep(2000);
            log.info("oneaccess用户删除成功-----------");
        } catch (Exception th) {
            log.error("线程sleep错误");
        }
        getAndDeleteOrg(idaasTenantId);
        // 报错回滚，删除之前的oneAccess数据
        String oneAccessAppId = idaas.getApplicationHttpsConsole().getAppId();
        getAndDeleteAccount(oneAccessAppId, oneAccessAccountId);
        throw new BizException(ExceptionCode.ONEACCESS_ADD_USER_FAILED.getCode(),
            ExceptionCode.ONEACCESS_ADD_USER_FAILED.getMsg());
    }

    private void insertDbReally(IdaasDto idaasDto) {
        log.info("insert database really");
        try {
            if (CheckNullUtil.isNull(idaasDto.getUserId()) && CheckNullUtil.isNull(idaasDto.getTenantId())) {
                // 插入企业
                encryptMsg(idaasDto.getTenant());
                tenantBaseMapper.insert(idaasDto.getTenant());
                // 插入组织
                orgBaseMapper.insert(idaasDto.getOrg());
                // 查询组织id,插入用户表
                QueryWrapper<Org> hslOrgQueryWrapper = new QueryWrapper<>();
                hslOrgQueryWrapper.select("id").eq("is_built_in", true).eq("is_del", false);
                Long orgId = orgBaseMapper.selectList(hslOrgQueryWrapper).get(0).getId();
                User user = idaasDto.getUser();
                user.setOrgId(orgId);
                // 插入用户
                user.setStatus(1);
                // 加密隐私信息
                encryptMsg(user);
                userBaseMapper.insert(user);

                // 初始化租户订阅app套餐的权限表
                initTenantSubscribableAppPackage();
            }
            if (CheckNullUtil.isNull(getAccountId(idaasDto.getUserId(), idaasDto.getSubAppId()))) {
                idaasDto.setUserId(getUserId().get(0).getId());
                // 插入角色和应用实体
                insertAppAndRole(idaasDto.getHslAppAccount(), idaasDto.getUserRole(),
                    idaasDto.getFinalOneAccessAccountId(), idaasDto.getUserId(), idaasDto.getRoleId(),
                    idaasDto.getSubAppId());
                // 插入应用账号
                appAccountBaseMapper.insert(idaasDto.getHslAppAccount());
                // 插入用户-角色关联表
                userRoleBaseMapper.insert(idaasDto.getUserRole());
                QueryWrapper<Tenant> hslTenantQueryWrapper = new QueryWrapper<>();
                hslTenantQueryWrapper.select("id").eq("is_built_in", true).eq("is_del", false);
                Long tenantId = tenantBaseMapper.selectList(hslTenantQueryWrapper).get(0).getId();
                log.info("----------------oneAccess初始化成功-------------------");
                // 插入企业套餐管理表
                initTenantApp(idaasDto, tenantId);

            }
        } catch (Exception e) {
            log.error("cloudServices insertDbReally exception", e);
            // 根据空判断是否为此次添加,如果存在,就删除回滚
            if (CheckNullUtil.isNotNull(idaasDto.getFinalOneAccessAccountId())) {
                String oneAccessAppId = idaas.getApplicationHttpsConsole().getAppId();
                getAndDeleteAccount(oneAccessAppId, idaasDto.getFinalOneAccessAccountId());
            }
            if (CheckNullUtil.isNotNull(idaasDto.getFinalOneAccessUserId())) {
                getAndDeleteUser(idaasDto.getFinalOneAccessUserId());
            }
            try {
                log.info("oneaccess用户删除中-----------");
                Thread.sleep(2000);
                log.info("oneaccess用户删除成功-----------");
            } catch (Exception th) {
                log.error("线程sleep错误");
            }
            if (CheckNullUtil.isNotNull(idaasDto.getFinalOneAccessTenantId())) {
                getAndDeleteOrg(idaasDto.getFinalOneAccessTenantId());
            }
            idaasDto.getTs().setRollbackOnly();
            throw new BizException("----------------插入oneAccess数据出错,请检查配置clean后重新install-------------------");
        }
    }

    public void initTenantSubscribableAppPackage() {
        List<Tenant> tenants = tenantBaseMapper
            .selectList(new QueryWrapper<Tenant>().eq("is_del", 0).eq("type", TenantTypeEnum.BUILT_IN.getType()));
        List<AppPackage> appPackages = appPackageBaseMapper.selectList(new QueryWrap<AppPackage>().eq("is_del", 0));
        List<TenantSubscribableAppPackage> tenantPackageList = new ArrayList<>();
        for (Tenant tenant : tenants) {
            for (AppPackage appPackage : appPackages) {
                TenantSubscribableAppPackage tenantPackage = new TenantSubscribableAppPackage();
                tenantPackage.setTenantId(tenant.getId())
                    .setTenantCode(tenant.getCode())
                    .setPackageId(appPackage.getId())
                    .setAppId(appPackage.getAppId())
                    .setExpireTime(DateUtils.NEVER_EXPIRE_DATETIME);
                tenantPackageList.add(tenantPackage);
            }
        }
        if (!CollectionUtils.isEmpty(tenantPackageList)) {
            tenantSubscribableAppPackageBaseMapper.insertBatchSomeColumn(tenantPackageList);
        }
    }

    private void encryptMsg(User user) {
        SaltDto platformSaltDto = workSecretKeyMapper.getPlatformSaltDto();
        String encrypt = EncryptionUtil.decrypt(platformSaltDto.getPwdSalt(), platformSaltDto.getPassword());
        if (ObjectUtil.isNotEmpty(user.getPhone())) {
            String phoneEncrypt = EncryptionUtil.encrypt(encrypt, user.getPhone());
            user.setPhone(phoneEncrypt);
        }
        if (ObjectUtil.isNotEmpty(user.getEmail())) {
            String emailEncrypt = EncryptionUtil.encrypt(encrypt, user.getEmail());
            user.setEmail(emailEncrypt);
        }
    }

    private void encryptMsg(Tenant tenant) {
        WorkSecretKey platformSaltDto = workSecretKeyMapper.selectOne(new QueryWrapper<WorkSecretKey>().lambda()
            .eq(WorkSecretKey::getTenantCode, tenant.getCode())
            .eq(WorkSecretKey::getIsDel, false));
        String encrypt = EncryptionUtil.decrypt(platformSaltDto.getPwdSalt(), platformSaltDto.getPassword());
        if (ObjectUtil.isNotEmpty(tenant.getPhone())) {
            String phoneEncrypt = EncryptionUtil.encrypt(encrypt, tenant.getPhone());
            tenant.setPhone(phoneEncrypt);
        }
    }

    private void initTenantApp(IdaasDto idaasDto, Long tenantId) {
        TenantApp hslTenantApp = new TenantApp();

        long appId = getAppId();
        long rdsId = getRdsId(appId);
        hslTenantApp.setAppId(idaasDto.getAppId())
            .setSubAppId(idaasDto.getSubAppId())
            .setTenantAppCode(idaasOrganization.getOrgCode())
            .setTenantCode(idaasOrganization.getOrgCode())
            .setTenantId(tenantId)
            .setRdsId(rdsId)
            .setIdaasClientId(idaasDto.getIdaasClientId())
            .setIdaasClientSecret(idaasDto.getIdaasClientSecret())
            .setIdaasAppId(idaasDto.getIdaasAppId())
            .setStatus(PackageStatusEnum.NORMAL.getStatus());
        tenantAppBaseMapper.insert(hslTenantApp);
    }

    private Long getAppId() {
        QueryWrapper<AppTemplate> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_del", 0).eq("type", 1);
        AppTemplate appTemplate = appTemplateBaseMapper.selectOne(queryWrapper);
        if (BeanPlusUtil.isEmpty(appTemplate)) {
            throw new BizException("未找到对应的应用模板");
        }
        return appTemplate.getId();
    }

    private long getRdsId(Long appId) {

        QueryWrapper<AppDeployment> deploymentInfoQueryWrapper = new QueryWrapper<>();
        deploymentInfoQueryWrapper.eq("app_id", appId).eq("is_del", 0);
        AppDeployment appDeployment = appDeploymentBaseMapper.selectOne(deploymentInfoQueryWrapper);
        if (BeanPlusUtil.isEmpty(appDeployment)) {
            throw new BizException("未找到对应的数据源信息");
        }
        return appDeployment.getRdsId();
    }

    /**
     * 获取数据库企业id
     *
     * @return 企业id
     */
    private List<Tenant> getTenantId() {

        QueryWrapper<Tenant> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id", "idaas_tenant_id").eq("name", idaasOrganization.getName()).eq("is_del", 0);
        return tenantBaseMapper.selectList(queryWrapper);
    }

    /**
     * 获取数据库应用id
     *
     * @return 应用id
     */
    private SubscribedApp getSubApp() {
        QueryWrapper<SubscribedApp> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_del", 0);
        List<SubscribedApp> subAppList = subscribedAppBaseMapper.selectList(queryWrapper);
        if (CheckNullUtil.isNotNull(subAppList)) {
            return subAppList.get(0);
        }
        return null;
    }

    /**
     * 获取数据库企业id
     *
     * @return 企业id
     */
    private List<Tenant> getAllTenantId() {

        QueryWrapper<Tenant> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id", "idaas_tenant_id").eq("is_del", 0);
        return tenantBaseMapper.selectList(queryWrapper);
    }

    /**
     * 获取本saas厂商的所有用户id
     *
     * @return 企业id
     */
    private List<IdaasUserProperties> getAllUser() {
        List<Tenant> allTenantId = getAllTenantId();
        List<String> tenantIdList = allTenantId.stream().map(Tenant::getIdaasTenantId).toList();
        if (tenantIdList.size() == 0) {
            return new ArrayList<>();
        }
        // 建立新的list,保存符合条件的结果
        List<IdaasUserProperties> idaasUser = Collections.synchronizedList(new ArrayList<>());
        log.info("-----------------开始多线程查询用户----------------");
        // stream->多线程执行user企业查询原居民,据.
        CompletableFuture<?>[] cfs = tenantIdList.stream()
            .map(tenantId -> CompletableFuture.supplyAsync(() -> getAllUser(tenantId), poolExecutor)
                .thenAccept(usersInOrg -> {
                    // 将jsonArray转换为list<实体类格式>
                    if (CheckNullUtil.isNull(usersInOrg)) {
                        return;
                    }
                    List<IdaasUserProperties> idaasUserList =
                        new ArrayList<>(JSONObject.parseArray(usersInOrg.toJSONString(), IdaasUserProperties.class));
                    // 如果用户的最高组织在企业表中存在,那么把该用户进行保存
                    idaasUser.addAll(idaasUserList);
                })
                .exceptionally(e -> {
                    // 截取错误信息
                    String message = e.getMessage();
                    log.error(message, e.toString());
                    throw new BizException(e);
                }))
            .toArray(CompletableFuture[]::new);
        // 等待总任务完成，但是无返回值，必须whenComplete()获取
        CompletableFuture.allOf((cfs)).join();
        log.info("-----------------多线程查询用户最高组织成功----------------");
        return idaasUser;
    }

    /**
     * 获取saas厂商所有的租户和组织
     *
     * @return 企业id
     */
    private List<IdaasOrganizationDto> getAllOrg() {
        List<Tenant> allTenant = getAllTenantId();
        List<String> tenantIdList = allTenant.stream().map(Tenant::getIdaasTenantId).toList();
        List<IdaasOrganizationDto> allOrg = Collections.synchronizedList(new ArrayList<>());
        if (CheckNullUtil.isNotNull(tenantIdList)) {
            CompletableFuture<?>[] cfs = tenantIdList.stream()
                .map(tenantId -> CompletableFuture.supplyAsync(() -> getAloneOrg(tenantId), poolExecutor)
                    .thenAccept(json -> {
                        if (CheckNullUtil.isNull(json)) {
                            return;
                        }
                        // 将jsonArray转换为list<实体类格式>
                        List<IdaasOrganizationDto> organizationListParent =
                            JSONObject.parseArray(json.toJSONString(), IdaasOrganizationDto.class);
                        allOrg.addAll(organizationListParent);
                    })
                    .exceptionally(e -> {
                        // 截取错误信息
                        String message = e.getMessage();
                        log.error(message);
                        throw new BizException(e);
                    }))
                .toArray(CompletableFuture[]::new);
            // 等待总任务完成，但是无返回值，必须whenComplete()获取
            CompletableFuture.allOf(cfs).join();
        }
        return allOrg;
    }

    /**
     * 获取数据库用户id
     *
     * @return 用户id
     */
    private List<User> getUserId() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id", "idaas_user_id").eq("user_name", idaasUserProperties.getUserName()).eq("is_del", 0);
        List<User> idList = userBaseMapper.selectList(queryWrapper);
        if (CheckNullUtil.isNotNull(idList)) {
            return idList;
        }
        return new ArrayList<>();
    }

    /**
     * 获取数据库应用账号id
     *
     * @return 应用账号id
     */
    public List<AppAccount> getAccountId(Long userId, Long appId) {
        if (CheckNullUtil.isNull(userId) || CheckNullUtil.isNull(appId)) {
            return new ArrayList<>();
        }
        QueryWrapper<AppAccount> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id", "idaas_account_id").eq("user_id", userId).eq("sub_app_id", appId).eq("is_del", 0);
        List<AppAccount> idList = appAccountBaseMapper.selectList(queryWrapper);
        if (CheckNullUtil.isNotNull(idList)) {
            return idList;
        }
        return new ArrayList<>();
    }

    /**
     * 获取数据库角色id
     *
     * @return 角色id
     */
    public Long getRoleId(Long appId) {
        Long roleId = null;
        QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id").eq("code", "PLATFORM_SYS_ADMIN").eq("sub_app_id", appId).eq("is_del", 0);
        List<Role> idList = roleBaseMapper.selectList(queryWrapper);
        if (CheckNullUtil.isNotNull(idList)) {
            roleId = idList.get(0).getId();
        }
        return roleId;
    }

    /**
     * 插入用户和企业实体
     *
     * @param user 用户实体
     * @param tenant 企业实体
     * @param org 组织实体
     * @param password 密码
     * @param oneAccessTenantId oneAccess企业id
     * @param idaasUserId oneAccess用户id
     * @param cmAccessKey 云商店卖家接入码
     */
    private void insertUserAndTenant(User user, Tenant tenant, Org org, String password, String oneAccessTenantId,
        String idaasUserId, String cmAccessKey, String idaasOrgId) {
        // 对用户信息进行加密
        // 插入企业实体
        tenant.setCode(idaasOrganization.getOrgCode())
            .setName(idaasOrganization.getName())
            .setIdaasTenantId(oneAccessTenantId)
            .setPhone(idaasUserProperties.getMobile())
            .setCmAccessKey(cmAccessKey)
            .setConsoleStatus("DEPLOY_SUCCEEDED")
            .setIsBuiltIn(true);
        // 插入组织实体
        org.setCode(idaasOrganization.getOrgCode())
            .setName(idaasOrganization.getName())
            .setIdaasOrgId(idaasOrgId)
            .setIsBuiltIn(true);
        // 插入用户实体
        user.setUserName(idaasUserProperties.getUserName())
            .setPhone(idaasUserProperties.getMobile())
            .setPassword(password)
            .setIdaasUserId(idaasUserId)
            .setIsBuiltIn(true)
            .setTenantCode(idaasOrganization.getOrgCode())
            .setTenantName(idaasOrganization.getName());
    }

    /**
     * 插入应用和角色相关实体
     *
     * @param hslAppAccount 应用实体
     * @param userRole 用户角色实体
     * @param idaasAccountId idaas应用账号id
     */
    private void insertAppAndRole(AppAccount hslAppAccount, UserRole userRole, String idaasAccountId, Long userId,
        Long roleId, Long appId) {
        // 插入应用账号实体
        hslAppAccount.setIdaasAccountId(idaasAccountId);
        // 查询数据库中oneAccessAppId对应的AppId
        // 插入用户应用关联实体
        hslAppAccount.setSubAppId(appId).setIdaasAccountId(idaasAccountId).setUserId(userId);
        // 插入用户角色关联实体
        if (userId != null && userId != 0L) {
            userRole.setUserId(userId);
        }
        if (roleId != null && roleId != 0L) {
            userRole.setRoleId(roleId);
        }
        if (appId != null && appId != 0L) {
            userRole.setSubAppId(appId);
        }
    }

    /**
     * @param json 用户/组织oneaccess连接获取的信息（例：user.getUserList(0, 100)）,用于获取用户/组织条数
     * @param listName 列表信息中的key：users/organizations
     * @param code 0 :获取所有用户信息 1 ：获取所有父组织信息 2 ：获取所有子组织信息 3:获取某个父组织下所有组织
     * @return oneaccess总的用户/组织列表信息(jsonArray)
     */
    protected JSONArray getOneAccessList(String json, String listName, Integer code, String orgId) {
        if (CheckNullUtil.isNull(json) || !json.contains("total")) {
            return new JSONArray();
        }

        // 查询出的用户总数
        int total = Integer.parseInt(JSONObject.parseObject(json).getOrDefault("total", 0).toString());

        // 以总数/单次查询数目 判断需要查询的次数
        int num = total % 100 != 0 ? total / 100 + 1 : total / 100;
        // 新建总的JsonArray,接收所有的数据
        JSONArray allInfo = new JSONArray();
        // 分页数据
        JSONArray objects;
        for (int offset = 0; offset < num; offset++) {
            // 0 :获取所有用户信息 1 ：获取所有父组织信息 2 ：获取所有子组织信息 3:获取某个组织下所有父组织,4,获取某个组织下的所有用户
            objects = getObjects(listName, code, offset, orgId);
            // 将单词查询数据放入总数据中
            allInfo.addAll(objects);
        }
        return allInfo;
    }

    /**
     * @param listName 列表信息中的key：users/organizations
     * @param code 0 :获取所有用户信息 1 ：获取所有父组织信息 2 ：获取所有子组织信息
     * @param offset 分页偏移量，表示从此偏移量开始查询， offset大于等于0。
     * @return oneaccess分页的用户/组织列表信息(jsonArray)
     */
    private JSONArray getObjects(String listName, Integer code, int offset, String orgId) {
        JSONArray objects;
        switch (code) {
            case 3:
                objects = getOrgAlone(listName, offset, orgId);
                break;
            case 4:
                objects = getUserListInOrg(listName, offset, orgId);
                break;
            default:
                objects = new JSONArray();
                break;
        }
        return objects;
    }

    private JSONArray getUserListInOrg(String listName, int offset, String orgId) {
        String s = getUserListInOrg(offset, 100, orgId);
        if (CheckNullUtil.isNull(s)) {
            return new JSONArray();
        } else {
            return JSONObject.parseObject(s).getJSONArray(listName);
        }
    }

    private JSONArray getOrgAlone(String listName, int offset, String orgId) {
        String s = getOrgAlone(offset, 100, orgId);
        if (CheckNullUtil.isNull(s)) {
            return new JSONArray();
        } else {
            return JSONObject.parseObject(s).getJSONArray(listName);
        }
    }
}
